<!--
  Copyright JS Foundation and other contributors, http://js.foundation

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->

<script type="text/html" data-template-name="http request">
    <div class="form-row">
        <label for="node-input-method"><i class="fa fa-tasks"></i> <span data-i18n="httpin.label.method"></span></label>
        <select type="text" id="node-input-method" style="width:70%;">
        <option value="GET">GET</option>
        <option value="POST">POST</option>
        <option value="PUT">PUT</option>
        <option value="DELETE">DELETE</option>
        <option value="HEAD">HEAD</option>
        <option value="use" data-i18n="httpin.setby"></option>
        </select>
    </div>

    <div class="form-row">
        <label for="node-input-url"><i class="fa fa-globe"></i> <span data-i18n="httpin.label.url"></span></label>
        <input id="node-input-url" type="text" placeholder="http://">
    </div>

    <div class="form-row node-input-paytoqs-row">
        <label for="node-input-paytoqs"><span data-i18n="common.label.payload"></span></label>
        <select id="node-input-paytoqs" style="width: 70%;">
            <option value="ignore" data-i18n="httpin.label.paytoqs.ignore"></option>
            <option value="query" data-i18n="httpin.label.paytoqs.query"></option>
            <option value="body" data-i18n="httpin.label.paytoqs.body"></option>
        </select>
    </div>

    <div class="form-row">
        <input type="checkbox" id="node-input-usetls" style="display: inline-block; width: auto; vertical-align: top;">
        <label for="node-input-usetls" style="width: auto" data-i18n="httpin.use-tls"></label>
        <div id="node-row-tls" class="hide">
            <label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-tls"><span data-i18n="httpin.tls-config"></span></label><input type="text" style="width: 300px" id="node-input-tls">
        </div>
    </div>

    <div class="form-row">
        <input type="checkbox" id="node-input-useAuth" style="display: inline-block; width: auto; vertical-align: top;">
        <label for="node-input-useAuth" style="width: 70%;"><span data-i18n="httpin.basicauth"></span></label>
        <div style="margin-left: 20px" class="node-input-useAuth-row hide">
            <div class="form-row">
                <label for="node-input-authType-select"><i class="fa fa-user-secret "></i> <span data-i18n="httpin.label.authType"></span></label>
                <select type="text" id="node-input-authType-select" style="width:70%;">
                    <option value="basic"  data-i18n="httpin.basic"></option>
                    <option value="digest" data-i18n="httpin.digest"></option>
                    <option value="bearer" data-i18n="httpin.bearer"></option>
                </select>
                <input type="hidden" id="node-input-authType">
            </div>
            <div class="form-row node-input-basic-row">
                <label for="node-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
                <input type="text" id="node-input-user">
            </div>
            <div class="form-row">
                <label for="node-input-password"> <i class="fa fa-lock"></i> <span data-i18n="common.label.password" id="node-span-password"></span><span data-i18n="httpin.label.bearerToken" id="node-span-token" style="display:none"></span></label>
                <input type="password" id="node-input-password">
            </div>
        </div>
    </div>

    <div class="form-row">
        <input type="checkbox" id="node-input-persist" style="display: inline-block; width: auto; vertical-align: top;">
        <label for="node-input-persist" style="width: auto" data-i18n="httpin.persist"></label>
    </div>

    <div class="form-row">
        <input type="checkbox" id="node-input-useProxy" style="display: inline-block; width: auto; vertical-align: top;">
        <label for="node-input-useProxy" style="width: auto;"><span data-i18n="httpin.use-proxy"></span></label>
        <div id="node-input-useProxy-row" class="hide">
            <label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-input-proxy"><i class="fa fa-globe"></i> <span data-i18n="httpin.proxy-config"></span></label><input type="text" style="width: 270px" id="node-input-proxy">
        </div>
    </div>

    <div class="form-row">
        <input type="checkbox" id="node-input-senderr" style="display: inline-block; width: auto; vertical-align: top;">
        <label for="node-input-senderr" style="width: auto" data-i18n="httpin.senderr"></label>
    </div>

    <div class="form-row">
        <input type="checkbox" id="node-input-insecureHTTPParser" style="display: inline-block; width: auto; vertical-align: top;">
        <label for="node-input-insecureHTTPParser" style="width: auto;" data-i18n="httpin.insecureHTTPParser"></label>
    </div>


    <div class="form-row">
        <label for="node-input-ret"><i class="fa fa-arrow-left"></i> <span data-i18n="httpin.label.return"></span></label>
        <select type="text" id="node-input-ret" style="width:70%;">
        <option value="txt" data-i18n="httpin.utf8"></option>
        <option value="bin" data-i18n="httpin.binary"></option>
        <option value="obj" data-i18n="httpin.json"></option>
        </select>
    </div>

    <div class="form-row form-tips" id="tip-json" hidden><span data-i18n="httpin.tip.req"></span></div>

    <div class="form-row" style="margin-bottom:0;">
        <label><i class="fa fa-list"></i> <span data-i18n="httpin.label.headers"></span></label>
    </div>
    <div class="form-row node-input-headers-container-row">
        <ol id="node-input-headers-container"></ol>
    </div>

    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
        <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
    </div>
</script>

<script type="text/javascript">
(function() {
    const headerTypes = [
        { value: "Accept", label: "Accept", hasValue: false },
        { value: "Accept-Encoding", label: "Accept-Encoding", hasValue: false },
        { value: "Accept-Language", label: "Accept-Language", hasValue: false },
        { value: "Authorization", label: "Authorization", hasValue: false },
        { value: "Content-Type", label: "Content-Type", hasValue: false },
        { value: "Cache-Control", label: "Cache-Control", hasValue: false },
        { value: "User-Agent", label: "User-Agent", hasValue: false },
        { value: "Location", label: "Location", hasValue: false },
        { value: "other", label: RED._("node-red:httpin.label.other"),
          hasValue: true, icon: "red/images/typedInput/az.svg" },
        { value: "msg", label: "msg.", hasValue: true },
    ]
    const headerOptions = {};
    const defaultOptions = [
        { value: "other", label: RED._("node-red:httpin.label.other"),
          hasValue: true, icon: "red/images/typedInput/az.svg" },
        { value: "msg", label: "msg.", hasValue: true },
    ];
    headerOptions["accept"] = [
        { value: "text/plain", label: "text/plain", hasValue: false },
        { value: "text/html", label: "text/html", hasValue: false },
        { value: "application/json", label: "application/json", hasValue: false },
        { value: "application/xml", label: "application/xml", hasValue: false },
        ...defaultOptions,
    ];
    headerOptions["accept-encoding"] = [
        { value: "gzip", label: "gzip", hasValue: false },
        { value: "deflate", label: "deflate", hasValue: false },
        { value: "compress", label: "compress", hasValue: false },
        { value: "br", label: "br", hasValue: false },
        { value: "gzip, deflate", label: "gzip, deflate", hasValue: false },
        { value: "gzip, deflate, br", label: "gzip, deflate, br", hasValue: false },
        ...defaultOptions,
    ];
    headerOptions["accept-language"] = [
        { value: "*", label: "*", hasValue: false },
        { value: "en-GB, en-US, en;q=0.9", label: "en-GB, en-US, en;q=0.9", hasValue: false },
        { value: "de-AT, de-DE;q=0.9, en;q=0.5", label: "de-AT, de-DE;q=0.9, en;q=0.5", hasValue: false },
        { value: "es-mx,es,en;q=0.5", label: "es-mx,es,en;q=0.5", hasValue: false },
        { value: "fr-CH, fr;q=0.9, en;q=0.8", label: "fr-CH, fr;q=0.9, en;q=0.8", hasValue: false },
        { value: "zh-CN, zh-TW; q = 0.9, zh-HK; q = 0.8, zh; q = 0.7, en; q = 0.6", label: "zh-CN, zh-TW; q = 0.9, zh-HK; q = 0.8, zh; q = 0.7, en; q = 0.6", hasValue: false },
        { value: "ja-JP, jp", label: "ja-JP, jp", hasValue: false },
        ...defaultOptions,
    ];
    headerOptions["content-type"] = [
        { value: "text/css", label: "text/css", hasValue: false },
        { value: "text/plain", label: "text/plain", hasValue: false },
        { value: "text/html", label: "text/html", hasValue: false },
        { value: "application/json", label: "application/json", hasValue: false },
        { value: "application/octet-stream", label: "application/octet-stream", hasValue: false },
        { value: "application/pdf", label: "application/pdf", hasValue: false },
        { value: "application/xml", label: "application/xml", hasValue: false },
        { value: "application/zip", label: "application/zip", hasValue: false },
        { value: "multipart/form-data", label: "multipart/form-data", hasValue: false },
        { value: "audio/aac", label: "audio/aac", hasValue: false },
        { value: "audio/ac3", label: "audio/ac3", hasValue: false },
        { value: "audio/basic", label: "audio/basic", hasValue: false },
        { value: "audio/mp4", label: "audio/mp4", hasValue: false },
        { value: "audio/ogg", label: "audio/ogg", hasValue: false },
        { value: "image/bmp", label: "image/bmp", hasValue: false },
        { value: "image/gif", label: "image/gif", hasValue: false },
        { value: "image/jpeg", label: "image/jpeg", hasValue: false },
        { value: "image/png", label: "image/png", hasValue: false },
        { value: "image/tiff", label: "image/tiff", hasValue: false },
        ...defaultOptions,
    ];
    headerOptions["cache-control"] = [
        { value: "max-age=0", label: "max-age=0", hasValue: false },
        { value: "max-age=86400", label: "max-age=86400", hasValue: false },
        { value: "no-cache", label: "no-cache", hasValue: false },
        ...defaultOptions,
    ];

    headerOptions["user-agent"] = [
        { value: "Mozilla/5.0", label: "Mozilla/5.0", hasValue: false },
        ...defaultOptions,
    ];

    function getHeaderOptions(headerName) {
        const lc = (headerName || "").toLowerCase();
        let opts = headerOptions[lc];
        return opts || defaultOptions;
    }

    RED.nodes.registerType('http request',{
        category: 'network',
        color:"rgb(231, 231, 174)",
        defaults: {
            name: {value:""},
            method:{value:"GET"},
            ret: {value:"txt"},
            paytoqs: {value: false},
            url:{
                value:"",
                validate: function(v, opt) {
                    if ((v.trim().length === 0) ||
                        (v.indexOf("://") === -1) ||
                        (v.trim().indexOf("http") === 0)) {
                        return true;
                    }
                    return RED._("node-red:httpin.errors.invalid-url");
                }
            },
            tls: {type:"tls-config",required: false,
                  label:RED._("node-red:httpin.tls-config") },
            persist: {value:false},
            proxy: {type:"http proxy",required: false,
                    label:RED._("node-red:httpin.proxy-config") },
            insecureHTTPParser: {value: false},
            authType: {value: ""},
            senderr: {value: false},
            headers: { value: [] }
        },
        credentials: {
            user: {type:"text"},
            password: {type: "password"}
        },
        inputs:1,
        outputs:1,
        outputLabels: function(i) {
            return ({
                txt: this._("httpin.label.utf8String"),
                bin: this._("httpin.label.binaryBuffer"),
                obj: this._("httpin.label.jsonObject")
            }[this.ret]);
        },
        icon: "white-globe.svg",
        label: function() {
            return this.name||this._("httpin.httpreq");
        },
        labelStyle: function() {
            return this.name?"node_label_italic":"";
        },
        oneditprepare: function() {
            const node = this;
            $("#node-input-useAuth").on("change", function() {
                if ($(this).is(":checked")) {
                    $(".node-input-useAuth-row").show();
                    // Nodes (< version 0.20.x) with credentials but without authentication type, need type 'basic'
                    if (!$('#node-input-authType').val()) {
                        $("#node-input-authType-select").val('basic').trigger("change");
                    }
                } else {
                    $(".node-input-useAuth-row").hide();
                    $('#node-input-authType').val('');
                    $('#node-input-user').val('');
                    $('#node-input-password').val('');
                }
                RED.tray.resize();
            });
            $("#node-input-authType-select").on("change", function() {
                const val = $(this).val();
                $("#node-input-authType").val(val);
                if (val === "basic" || val === "digest") {
                    $(".node-input-basic-row").show();
                    $('#node-span-password').show();
                    $('#node-span-token').hide();
                } else if (val === "bearer") {
                    $(".node-input-basic-row").hide();
                    $('#node-span-password').hide();
                    $('#node-span-token').show();
                    $('#node-input-user').val('');
                }
                RED.tray.resize();
            });
            $("#node-input-method").on("change", function() {
                if ($(this).val() == "GET") {
                    $(".node-input-paytoqs-row").show();
                } else {
                    $(".node-input-paytoqs-row").hide();
                }
                RED.tray.resize();
            });
            if (node.paytoqs === true || node.paytoqs == "query") {
                $("#node-input-paytoqs").val("query");
            } else if (node.paytoqs === "body") {
                $("#node-input-paytoqs").val("body");
            } else {
                $("#node-input-paytoqs").val("ignore");
            }
            if (node.authType) {
                $('#node-input-useAuth').prop('checked', true);
                $("#node-input-authType-select").val(node.authType);
                $("#node-input-authType-select").change();
            } else {
                $('#node-input-useAuth').prop('checked', false);
            }
            $("#node-input-useAuth").change();

            function updateTLSOptions() {
                if ($("#node-input-usetls").is(':checked')) {
                    $("#node-row-tls").show();
                } else {
                    $("#node-row-tls").hide();
                }
                RED.tray.resize();
            }
            if (node.tls) {
                $('#node-input-usetls').prop('checked', true);
            } else {
                $('#node-input-usetls').prop('checked', false);
            }
            updateTLSOptions();
            $("#node-input-usetls").on("click",function() {
                updateTLSOptions();
            });

            function updateProxyOptions() {
                if ($("#node-input-useProxy").is(":checked")) {
                    $("#node-input-useProxy-row").show();
                } else {
                    $("#node-input-useProxy-row").hide();
                }
                RED.tray.resize();
            }
            if (node.proxy) {
                $("#node-input-useProxy").prop("checked", true);
            } else {
                $("#node-input-useProxy").prop("checked", false);
            }

            if (node.insecureHTTPParser) {
                $("node-intput-insecureHTTPParser").prop("checked", true)
            } else {
                $("node-intput-insecureHTTPParser").prop("checked", false)
            }
            updateProxyOptions();
            $("#node-input-useProxy").on("click", function() {
                updateProxyOptions();
            });

            $("#node-input-ret").on("change", function() {
                if ($("#node-input-ret").val() === "obj") {
                    $("#tip-json").show();
                } else {
                    $("#tip-json").hide();
                }
                RED.tray.resize();
            });
            const hasMatch = function (arr, value) {
                return arr.some(function (ht) {
                    return ht.value === value
                });
            }
            const headerList = $("#node-input-headers-container").css('min-height', '150px').css('min-width', '450px').editableList({
                addItem: function (container, i, header) {
                    const row = $('<div/>').css({
                        overflow: 'hidden',
                        whiteSpace: 'nowrap',
                        display: 'flex'
                    }).appendTo(container);
                    const propertNameCell = $('<div/>').css({ 'flex-grow': 1 }).appendTo(row);
                    const propertyName = $('<input/>', { class: "node-input-header-name", type: "text", style: "width: 100%" })
                        .appendTo(propertNameCell)
                        .typedInput({ types: headerTypes });

                    const propertyValueCell = $('<div/>').css({ 'flex-grow': 1, 'margin-left': '10px' }).appendTo(row);
                    const propertyValue = $('<input/>', { class: "node-input-header-value", type: "text", style: "width: 100%" })
                        .appendTo(propertyValueCell)
                        .typedInput({
                            types: getHeaderOptions(header.keyType)
                        });

                    const setup = function(_header) {
                        const headerTypeIsAPreset = function(h) {return hasMatch(headerTypes, h) };
                        const headerValueIsAPreset = function(h, v) {return hasMatch(getHeaderOptions(h), v) };
                        const {keyType, keyValue, valueType, valueValue} = header;
                        if(keyType == "msg" || keyType == "other") {
                            propertyName.typedInput('type', keyType);
                            propertyName.typedInput('value', keyValue);
                        } else if (headerTypeIsAPreset(keyType)) {
                            propertyName.typedInput('type', keyType);
                        } else {
                            propertyName.typedInput('type', "other");
                            propertyName.typedInput('value', keyValue);
                        }
                        if(valueType == "msg" || valueType == "other") {
                            propertyValue.typedInput('type', valueType);
                            propertyValue.typedInput('value', valueValue);
                        } else if (headerValueIsAPreset(propertyName.typedInput('type'), valueType)) {
                            propertyValue.typedInput('type', valueType);
                        } else {
                            propertyValue.typedInput('type', "other");
                            propertyValue.typedInput('value', valueValue);
                        }
                    }
                    setup(header);

                    propertyName.on('change', function (event) {
                        propertyValue.typedInput('types', getHeaderOptions(propertyName.typedInput('type')));
                    });

                },
                sortable: true,
                removable: true
            });
            if (node.headers) {
                for (let index = 0; index < node.headers.length; index++) {
                    const element = node.headers[index];
                    headerList.editableList('addItem', node.headers[index]);
                }
            }
        },
        oneditsave: function() {
            if (!$("#node-input-usetls").is(':checked')) {
                $("#node-input-tls").val("_ADD_");
            }
            if (!$("#node-input-useProxy").is(":checked")) {
                $("#node-input-proxy").val("_ADD_");
            }
            const headers = $("#node-input-headers-container").editableList('items');
            const node = this;
            node.headers = [];
            headers.each(function(i) {
                const header = $(this);
                const keyType = header.find(".node-input-header-name").typedInput('type');
                const keyValue = header.find(".node-input-header-name").typedInput('value');
                const valueType = header.find(".node-input-header-value").typedInput('type');
                const valueValue = header.find(".node-input-header-value").typedInput('value');
                if (keyType !== '' || keyType === 'other' || keyType === 'msg') {
                    node.headers.push({
                        keyType, keyValue, valueType, valueValue
                    })
                }
            });
        },
        oneditresize: function(size) {
            const dlg = $("#dialog-form");
            const expandRow = dlg.find('.node-input-headers-container-row');
            let height = dlg.height() - 5;
            if(expandRow && expandRow.length){
                const siblingRows = dlg.find('> .form-row:not(.node-input-headers-container-row)');
                for (let i = 0; i < siblingRows.size(); i++) {
                    const cr = $(siblingRows[i]);
                    if(cr.is(":visible"))
                        height -= cr.outerHeight(true);
                }
                $("#node-input-headers-container").editableList('height',height);
            } 
        }
    });
})();    
</script>
